package com.qfmy.web.app.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/**
 * @author 清风明月
 * @Package com.qfmy.web.app.filter
 * @date 2025/9/18
 * @description 自定义敏感词过滤器（基于DFA算法，从文件加载敏感词）
 */
@Slf4j
@Component
public class SensitiveWordFilter {

     // DFA算法的"根节点"，存储所有敏感词的前缀树结构
     private final Map<String, Object> sensitiveWordTree = new HashMap<>();

     // 敏感词总数
     private int sensitiveWordCount = 0;

     /**
      * 初始化：从文件加载敏感词并构建DFA前缀树
      */
     public SensitiveWordFilter() {
      Set<String> sensitiveWords = loadSensitiveWordsFromFile();
      if (!sensitiveWords.isEmpty()) {
       buildSensitiveWordTree(sensitiveWords);
       this.sensitiveWordCount = sensitiveWords.size();
      }
     }

     /**
      * 从classpath下的SensitiveWord.txt文件读取敏感词（逗号分隔）
      * @return 敏感词集合
      */
     private Set<String> loadSensitiveWordsFromFile() {
      Set<String> sensitiveWords = new HashSet<>();
      ClassPathResource resource = new ClassPathResource("SensitiveWord.txt");

      try (BufferedReader reader = new BufferedReader(
              new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {

       String line;
       while ((line = reader.readLine()) != null) {
        // 处理每行内容
        String trimmedLine = line.trim();
        if (trimmedLine.isEmpty()) {
         continue; // 跳过空行
        }

        // 按逗号分割并处理每个敏感词
        String[] words = trimmedLine.split(",");
        for (String word : words) {
         String trimmedWord = word.trim();
         if (!trimmedWord.isEmpty()) {
          sensitiveWords.add(trimmedWord);
         }
        }
       }
      } catch (IOException e) {
       log.error("Error reading sensitive words file: {}", e.getMessage());
      }
      return sensitiveWords;
     }

 /**
  * 构建敏感词的DFA前缀树
  * @param sensitiveWords 敏感词集合
  */
 private void buildSensitiveWordTree(Set<String> sensitiveWords) {
  for (String word : sensitiveWords) {
   Map<String, Object> currentNode = sensitiveWordTree;

   for (int i = 0; i < word.length(); i++) {
    char c = word.charAt(i);
    String key = String.valueOf(c);

    // 检查当前节点是否存在该字符的子节点
    @SuppressWarnings("unchecked")
    Map<String, Object> childNode = (Map<String, Object>) currentNode.get(key);

    if (childNode == null) {
     // 不存在则创建新的子节点
     childNode = new HashMap<>();
     currentNode.put(key, childNode);
    }

    // 移动到子节点
    currentNode = childNode;

    // 标记敏感词结束
    if (i == word.length() - 1) {
     currentNode.put("isEnd", true);
    }
   }
  }
 }

 /**
  * 检测文本是否包含敏感词
  * @param text 待检测文本
  * @return true=包含敏感词，false=不包含
  */
 public boolean isSensitive(String text) {
  if (text == null || text.trim().isEmpty() || sensitiveWordCount == 0) {
   return false;
  }

  String trimmedText = text.trim();

  // 遍历文本每个字符作为起始点检测
  for (int i = 0; i < trimmedText.length(); i++) {
   if (checkSensitive(trimmedText, i)) {
    return true;
   }
  }
  return false;
 }

 /**
  * 从指定位置开始检测是否有敏感词匹配
  * @param text 待检测文本
  * @param startIndex 起始位置
  * @return true=匹配到敏感词，false=未匹配
  */
 private boolean checkSensitive(String text, int startIndex) {
  Map<String, Object> currentNode = sensitiveWordTree;
  boolean isMatch = false;
  int matchLength = 0;

  for (int i = startIndex; i < text.length(); i++) {
   char c = text.charAt(i);
   String key = String.valueOf(c);

   // 获取子节点
   @SuppressWarnings("unchecked")
   Map<String, Object> childNode = (Map<String, Object>) currentNode.get(key);

   if (childNode == null) {
    break; // 没有匹配的子节点，结束检测
   }

   matchLength++;
   currentNode = childNode;

   // 找到完整的敏感词
   if (currentNode.containsKey("isEnd")) {
    isMatch = true;
    break;
   }
  }

  // 只有匹配长度大于0且确实匹配到敏感词才算有效
  return matchLength > 0 && isMatch;
 }

 /**
  * 替换文本中的敏感词为*
  * @param text 待处理文本
  * @return 替换后的文本
  */
 public String replaceSensitive(String text) {
  if (text == null || sensitiveWordCount == 0) {
   return text;
  }

  StringBuilder result = new StringBuilder(text);

  for (int i = 0; i < result.length(); i++) {
   // 检查从当前位置开始是否有敏感词
   int sensitiveLength = getSensitiveWordLength(result.toString(), i);
   if (sensitiveLength > 0) {
    // 替换敏感词为*
    for (int j = 0; j < sensitiveLength; j++) {
     result.setCharAt(i + j, '*');
    }
    // 跳过已处理的敏感词
    i += sensitiveLength - 1;
   }
  }

  return result.toString();
 }

 /**
  * 获取从指定位置开始的敏感词长度
  * @param text 待检测文本
  * @param startIndex 起始位置
  * @return 敏感词长度，0表示未匹配
  */
 private int getSensitiveWordLength(String text, int startIndex) {
  Map<String, Object> currentNode = sensitiveWordTree;
  int length = 0;
  int maxLength = 0;

  for (int i = startIndex; i < text.length(); i++) {
   char c = text.charAt(i);
   String key = String.valueOf(c);

   @SuppressWarnings("unchecked")
   Map<String, Object> childNode = (Map<String, Object>) currentNode.get(key);

   if (childNode == null) {
    break;
   }

   length++;
   currentNode = childNode;

   // 记录最长匹配的敏感词长度
   if (currentNode.containsKey("isEnd")) {
    maxLength = length;
   }
  }

  return maxLength;
 }


}
